package com.zmn.plat.business.impl.price;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.plat.business.interfaces.brand.ratio.BrandRatioBService;
import com.zmn.plat.business.interfaces.channel.ChannelCityPriceRatioBService;
import com.zmn.plat.business.interfaces.channel.ChannelServiceCategoryBService;
import com.zmn.plat.business.interfaces.pilot.ChannelPriceBService;
import com.zmn.plat.business.interfaces.price.CommonBService;
import com.zmn.plat.business.interfaces.product.ServProductBService;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.common.dictionary.BaseCityPriceTypeEnum;
import com.zmn.plat.common.dictionary.ChannelCityRatioTypeEnum;
import com.zmn.plat.common.dto.brand.factor.BrandFactorDRO;
import com.zmn.plat.common.dto.price.ItemTo;
import com.zmn.plat.common.dto.price.RatioTo;
import com.zmn.plat.common.enums.PilotConfigEnum;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.manager.dictionary.ProductDict;
import com.zmn.plat.model.dto.price.PriceCalDTO;
import com.zmn.plat.model.dto.product.ProductRelationDTO;
import com.zmn.plat.model.entity.base.difficult.ratio.DifficultRatio;
import com.zmn.plat.model.entity.channel.ChannelCityPriceRatio;
import com.zmn.plat.model.entity.channel.ChannelCityPriceRatioQuery;
import com.zmn.plat.model.entity.channel.brand.ratio.ChannelBrandAllLevelRatioQuery;
import com.zmn.plat.model.entity.product.ServProduct;
import com.zmn.plat.model.entity.product.tariff.ProductTariffQuery;
import com.zmn.plat.model.entity.product.tariff.item.ProductTariffGroupItemQuery;
import com.zmn.plat.model.entity.service.tariff.ServiceTariffQuery;
import com.zmn.plat.model.vo.channel.brand.ratio.ChannelBrandRatioAllLevelVo;
import com.zmn.plat.model.vo.product.tariff.ProductTariffVO;
import com.zmn.plat.model.vo.service.tariff.ChannelServiceTariffVO;
import com.zmn.plat.services.interfaces.base.difficult.ratio.DifficultRatioService;
import com.zmn.plat.services.interfaces.channel.ChannelCityPriceRatioService;
import com.zmn.plat.services.interfaces.channel.brand.ratio.ChannelBrandRatioService;
import com.zmn.plat.services.interfaces.channel.tariff.ChannelTariffService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.product.tariff.ProductTariffService;
import com.zmn.plat.services.interfaces.product.tariff.item.ProductTariffGroupItemService;
import com.zmn.plat.services.interfaces.service.tariff.ServiceTariffService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 描述: 公共服务实现类
 *
 * @author guoqiao
 * @since 2021/8/27 10:58
 */
@Slf4j
@Service
public class CommonBServiceImpl implements CommonBService {

    // 默认系数
    private final static Float RESULT_RATIO = 1.0F;
    // 系数不存在缓存值给定值
    private final static Float CACHE_DEFAULT_RATIO = -1.0F;
    @Resource
    ChannelCityPriceRatioService channelCityPriceRatioService;
    @Resource
    BrandRatioBService brandRatioBService;
    @Resource
    ChannelCityPriceRatioBService channelCityPriceRatioBService;
    @Resource
    ServProductService servProductService;
    @Resource
    ChannelBrandRatioService channelBrandRatioService;
    @Resource
    DifficultRatioService difficultRatioService;
    @Resource
    ServProductBService servProductBService;
    @Resource
    ChannelTariffService channelTariffService;
    @Resource
    ProductTariffService productTariffService;
    @Resource
    ServiceTariffService serviceTariffService;
    @Resource
    ProductTariffGroupItemService productTariffGroupItemService;
    @Resource
    ChannelPriceBService channelPriceBService;
    @Resource
    ChannelServiceCategoryBService channelServiceCategoryBService;
    @Resource
    CommonBService commonBService;

    // 考虑难度系数的情况下价格的最小值
    private static final int MIN_PRICE_FEN = 15000;
    // 普通故障类型id
    private static final int FAULT_CATEG_ID_NORMAL = 1000;
    // 难度系数只应用于普通故障和特殊故障
    private static final List<Integer> DIFFICULT_LIST = Arrays.asList(1000, 1002);

    // 流程中只有普通故障和服务收费才能报价（计价器报价）
    private static final List<Integer> ITEM_CATEG_LIST = Arrays.asList(1000, 1005);

    // 本缓存时间
    private static final int MAX_CACHE_EXP = 6;
    // 渠道折扣本地缓存
    private Cache<String, Float> channelDiscountCache = CacheBuilder.newBuilder().expireAfterWrite(MAX_CACHE_EXP, TimeUnit.HOURS).build();
    // 城市系数本地缓存
    private Cache<String, Float> cityCache = CacheBuilder.newBuilder().expireAfterWrite(MAX_CACHE_EXP, TimeUnit.HOURS).build();
    // 品牌系数本地缓存
    private Cache<String, Float> brandCache = CacheBuilder.newBuilder().expireAfterWrite(MAX_CACHE_EXP, TimeUnit.HOURS).build();
    // 难度系数本地缓存
    private Cache<Integer, DifficultRatio> difficultCache = CacheBuilder.newBuilder().expireAfterWrite(MAX_CACHE_EXP, TimeUnit.HOURS).build();

    @Override
    public void calPriceDetail(ItemTo itemTo, PriceCalDTO calDTO) {

        if (!Objects.equals(itemTo.getPriceStandard(), GlobalConsts.YES)) {
            log.info("calPriceDetail非一口价不计算价格，项目id:{}", itemTo.getItemId());
            return;
        }
        Integer bizType = calDTO.getBizType();
        // 获取系数（渠道折扣，城市系数，品牌系数，分为内外部不同类型）
        RatioTo ratioTo = this.fillRatio(itemTo, calDTO);
        log.info("系数To为：{}", ratioTo);

        // 填充销售价格
        this.fillPrice(itemTo, ratioTo, bizType);

        // 填充销内部价
        this.fillInnerPrice(itemTo, ratioTo, bizType);
    }

    /**
     * 填充销售价格
     */
    private void fillPrice(ItemTo itemTo, RatioTo ratioTo, Integer bizType) {
        Integer price = itemTo.getPrice();
        Float difficultRatio = Objects.isNull(ratioTo.getDifficultRatio()) ? 0f : ratioTo.getDifficultRatio().floatValue();
        if (NumberUtil.isNullOrZero(price)) {
            return;
        }
        Integer minPrice = price;
        // 如果区分明细 且 区分明细为1 则填充明细费用和最低价
        boolean isLimitByPrice = Objects.equals(itemTo.getPriceSplit(), GlobalConsts.YES) && Objects.equals(itemTo.getPriceSplitType(), GlobalConsts.NO);
        if (isLimitByPrice) {
            // 填充明细费用和最低价
            this.fillDetailOne(itemTo, bizType);
            // 最低价格
            minPrice = itemTo.getMinPrice();
        }
        // 渠道折扣
        Integer channelDisCountPrice = PriceUtil.getPriceBy689(price, ratioTo.getChannelDiscont(), bizType);
        if (isLimitByPrice && channelDisCountPrice.compareTo(minPrice) < 0) {
            channelDisCountPrice = minPrice;
        }

        // 计算价格城市价
        Integer cityPrice = channelDisCountPrice;
        if (Objects.equals(itemTo.getCityLimit(), GlobalConsts.YES)) {
            cityPrice = PriceUtil.getPriceBy689(channelDisCountPrice, ratioTo.getCityRatio(), bizType);
            if (isLimitByPrice && cityPrice.compareTo(minPrice) < 0) {
                cityPrice = minPrice;
            }
        }
        // 品牌系数
        Integer brandPrice = cityPrice;
        if (Objects.equals(itemTo.getBrandLimit(), GlobalConsts.YES)) {
            brandPrice = PriceUtil.getPriceBy689(cityPrice, ratioTo.getBrandRatio(), bizType);
            if (isLimitByPrice && brandPrice.compareTo(minPrice) < 0) {
                brandPrice = minPrice;
            }
        }
        // 难度系数
        Integer difficultPrice = brandPrice;
        if (Objects.equals(true, ratioTo.getDifficultLimit())) {
            difficultPrice = PriceUtil.getPriceBy689(difficultPrice, difficultRatio, bizType);
            if (isLimitByPrice && difficultPrice.compareTo(minPrice) < 0) {
                difficultPrice = minPrice;
            }
        }
        price = difficultPrice;

        // 销售价
        itemTo.setPrice(price);

        if (isLimitByPrice) {
            // 再次填充明细一费用
            this.fillDetailOne(itemTo, bizType);
        }

        // 一口价区分明细，且是明细二的，计算工艺费等
        boolean isDetailTwo = Objects.equals(itemTo.getPriceSplit(), GlobalConsts.YES) && Objects.equals(itemTo.getPriceSplitType(), GlobalConsts.YES);
        if (isDetailTwo) {
            this.fillDetailTwo(itemTo);
        }

        // 如果是普通故障，同时价格小于150，同时考虑难度系数,同时满足一口价区分明细明细类型1的，修改区分明细为不区分
        if (Objects.equals(FAULT_CATEG_ID_NORMAL, itemTo.getItemCategId()) && price < MIN_PRICE_FEN
                && Objects.equals(true, ratioTo.getDifficultLimit())) {
            itemTo.setPriceSplit(GlobalConsts.NO);
        }
    }

    /**
     * 填充内部价格
     */
    private void fillInnerPrice(ItemTo itemTo, RatioTo ratioTo, Integer bizType) {
        Integer price = itemTo.getInternalSettlementPrice();
        Float difficultRatio = Objects.isNull(ratioTo.getDifficultRatio()) ? 0f : ratioTo.getDifficultRatio().floatValue();
        if (NumberUtil.isNotNullOrZero(price)) {
            price = PriceUtil.getPriceBy689(price, ratioTo.getInternalChannelDiscont(), bizType);
            if (Objects.equals(itemTo.getCityLimit(), GlobalConsts.YES)) {
                price = PriceUtil.getPriceBy689(price, ratioTo.getInternalCityRatio(), bizType);
            }
            if (Objects.equals(itemTo.getBrandLimit(), GlobalConsts.YES)) {
                price = PriceUtil.getPriceBy689(price, ratioTo.getInternalBrandRatio(), bizType);
            }
            if (Objects.equals(ratioTo.getEffectInnerPrice(), GlobalConsts.YES)) {
                price = PriceUtil.getPriceBy689(price, difficultRatio, bizType);
            }
            itemTo.setInternalSettlementPrice(price);
        }
    }

    /**
     * 填充明细一费用和最低价
     */
    private void fillDetailOne(ItemTo itemTo, Integer bizType) {
        // 销售价
        BigDecimal priceBig = new BigDecimal(itemTo.getPrice());

        // 交通费
        BigDecimal trafficFeeBig = new BigDecimal(itemTo.getTrafficFee());
        // 工时费
        BigDecimal hourFeeBig = new BigDecimal(itemTo.getHourFee());
        // 检测费
        BigDecimal checkFeeBig = new BigDecimal(itemTo.getCheckFee());

        // 配件包干费
        BigDecimal partRatio = Objects.isNull(itemTo.getPartRatio()) ? BigDecimal.ZERO : itemTo.getPartRatio();
        BigDecimal partRatioPercent = partRatio.divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal partPriceBig = priceBig.multiply(partRatioPercent);
        itemTo.setPartPrice(partPriceBig.intValue() / 100 * 100);

        // 工艺费
        BigDecimal artRatio = Objects.isNull(itemTo.getArtRatio()) ? BigDecimal.ZERO : itemTo.getArtRatio();
        BigDecimal artRatioPercent = artRatio.divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal artPriceBig = priceBig.multiply(artRatioPercent);
        itemTo.setArtPrice(artPriceBig.intValue() / 100 * 100);

        // 保修费
        BigDecimal guaranteeRatio = Objects.isNull(itemTo.getGuaranteeRatio()) ? BigDecimal.ZERO : itemTo.getGuaranteeRatio();
        BigDecimal guaranteeRatioPercent = guaranteeRatio.divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal guaranteePriceBig = priceBig.multiply(guaranteeRatioPercent);
        itemTo.setGuaranteePrice(guaranteePriceBig.intValue() / 100 * 100);

        BigDecimal temPrice = trafficFeeBig.add(hourFeeBig).add(checkFeeBig).add(new BigDecimal(itemTo.getPartPrice())).add(new BigDecimal(itemTo.getArtPrice())).add(new BigDecimal(itemTo.getGuaranteePrice()));

        // 技术服务费
        Integer servicePrice = priceBig.subtract(temPrice).intValue();
        itemTo.setServicePrice(servicePrice);

        // 最低价
        Integer minPrice = PriceUtil.getPriceBy689(temPrice.intValue(), RESULT_RATIO, bizType);
        itemTo.setMinPrice(minPrice);
    }

    /**
     * 填充明细二费用
     */
    private void fillDetailTwo(ItemTo itemTo) {
        // 销售价
        BigDecimal priceBig = new BigDecimal(itemTo.getPrice());

        // 材料费（明细二）
        BigDecimal materialFee = Objects.isNull(itemTo.getMaterialFee()) ? BigDecimal.ZERO : itemTo.getMaterialFee();
        BigDecimal materialPercent = materialFee.divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal materialFeeBig = priceBig.multiply(materialPercent);
        itemTo.setMaterialPrice(materialFeeBig.intValue() / 100 * 100);
        // 工艺费（明细二）
        itemTo.setArtPriceDetailTwo(priceBig.subtract(new BigDecimal(itemTo.getMaterialPrice())).intValue());
    }

    /**
     * 获取系数（渠道、品牌、难度）
     */
    private RatioTo fillRatio(ItemTo itemTo, PriceCalDTO calDTO) {
        Integer channelId = calDTO.getChannelId();
        Integer cityId = calDTO.getCityId();
        Integer brandId = calDTO.getBrandId();
        Integer difficultId = calDTO.getDifficultId();
        Integer bizType = calDTO.getBizType();

        RatioTo ratioTo = new RatioTo();
        ratioTo.setItemId(itemTo.getItemId());
        ratioTo.setProductId(itemTo.getProductId());
        // 获取品牌系数
        if (NumberUtil.isNotNullOrZero(brandId)) {
            Float brandRatio = getBrandRatio(channelId, brandId, itemTo.getProductId(), bizType, BaseCityPriceTypeEnum.PRICE.getCode());
            Float internalBrandRatio = getBrandRatio(channelId, brandId, itemTo.getProductId(), bizType, BaseCityPriceTypeEnum.INNERPRICE.getCode());
            ratioTo.setBrandRatio(brandRatio);
            ratioTo.setInternalBrandRatio(internalBrandRatio);
        }
        // 系数定价需要考虑品牌系数，折扣，城市系数，城市定价只考虑品牌系数
        if (Objects.equals(itemTo.getPriceType(), ProductDict.TRIFF_PRICE_TYPE_RATIO)) {
            // 渠道折扣
            if (NumberUtil.isNotNullOrZero(channelId)) {
                Float channelDiscont = getChannelDiscount(channelId, bizType, BaseCityPriceTypeEnum.PRICE.getCode());
                Float internalChannelDiscont = getChannelDiscount(channelId, bizType, BaseCityPriceTypeEnum.INNERPRICE.getCode());
                ratioTo.setChannelDiscont(channelDiscont);
                ratioTo.setInternalChannelDiscont(internalChannelDiscont);
            }

            // 城市系数
            if (NumberUtil.isNotNullOrZero(cityId)) {
                Float cityRatio = getCityRatio(channelId, cityId, itemTo.getProductId(), bizType, BaseCityPriceTypeEnum.PRICE.getCode());
                Float internalCityRatio = getCityRatio(channelId, cityId, itemTo.getProductId(), bizType, BaseCityPriceTypeEnum.INNERPRICE.getCode());
                ratioTo.setCityRatio(cityRatio);
                ratioTo.setInternalCityRatio(internalCityRatio);
            }
        }

        // 难度系数只应用于普通故障和特殊故障
        if (NumberUtil.isNotNullOrZero(difficultId) && DIFFICULT_LIST.contains(itemTo.getItemCategId())) {
            DifficultRatio ratio = getDifficultRatio(difficultId);
            if (NumberUtil.isNotNullOrZero(ratio.getDifficultId())) {
                ratioTo.setDifficultRatio(ratio.getRatio());
                ratioTo.setEffectInnerPrice(ratio.getEffectInnerPrice());
                ratioTo.setDifficultLimit(true);
            }
        }
        return ratioTo;
    }

    /**
     * 描述: 获取渠道系数
     *
     * @param channelId 渠道id
     * @param bizType   业务类型
     * @param priceType 1销售价 2内部价
     * @return java.lang.Float
     * @author guoqiao
     * @since 2021/8/27 11:06
     */
    private Float getChannelDiscount(Integer channelId, Integer bizType, Integer priceType) {
        try {
            String key = channelId + "_" + bizType + "_" + priceType;
            return channelDiscountCache.get(key, () -> {
                ChannelCityPriceRatioQuery channelCityPriceRatioQuery = new ChannelCityPriceRatioQuery();
                channelCityPriceRatioQuery.setChannelId(channelId);
                channelCityPriceRatioQuery.setBizType(bizType);
                channelCityPriceRatioQuery.setPriceType(priceType);
                channelCityPriceRatioQuery.setRatioType(ChannelCityRatioTypeEnum.DISCOUNTRATIO.getCode());
                ChannelCityPriceRatio channelCityPriceRatio = channelCityPriceRatioService.findByChannelIdAndCityAndCategAndType(channelCityPriceRatioQuery);
                Float channelDisconut = CACHE_DEFAULT_RATIO;
                if (Objects.isNull(channelCityPriceRatio)) {
                    return channelDisconut;
                }
                Double ratio = channelCityPriceRatio.getRatio();
                if (PriceUtil.isPositive(ratio)) {
                    channelDisconut = new BigDecimal(ratio).floatValue();
                }
                return channelDisconut;
            });
        } catch (Exception e) {
            log.error("缓存方式获取渠道折扣失败:{},", e);
            throw new PlatException("缓存方式获取渠道折扣失败");
        }
    }

    /**
     * 描述: 获取城市系数
     *
     * @param channelId     渠道id
     * @param cityId        城市id
     * @param productId     后台产品id
     * @param bizType       业务类型
     * @param cityPriceType 1销售价 2内部价
     * @return java.lang.Float
     * @author guoqiao
     * @since 2021/8/27 11:06
     */
    private Float getCityRatio(Integer channelId, Integer cityId, Integer productId, Integer bizType, Integer cityPriceType) {
        try {
            String key = channelId + "_" + cityId + "_" + productId + "_" + bizType + "_" + cityPriceType;
            return cityCache.get(key, () -> {
                Float ratio = channelCityPriceRatioBService.findRatioByChannelIdAndCityId(channelId, cityId, productId, bizType, cityPriceType);
                return PriceUtil.isPositive(ratio) ? ratio : CACHE_DEFAULT_RATIO;
            });
        } catch (Exception e) {
            log.error("缓存方式获取城市系数失败:{},", e);
            throw new PlatException("缓存方式获取城市系数失败");
        }
    }

    /**
     * 描述: 获取品牌系数
     *
     * @param channelId      渠道id
     * @param brandId        品牌id
     * @param productId      后台产品id
     * @param bizType        业务类型
     * @param brandPriceType 1销售价 2内部价
     * @return java.lang.Float
     * @author guoqiao
     * @since 2021/8/27 11:06
     */
    private Float getBrandRatio(Integer channelId, Integer brandId, Integer productId, Integer bizType, Integer brandPriceType) {
        try {
            String key = channelId + "_" + brandId + "_" + productId + "_" + bizType + "_" + brandPriceType;
            return brandCache.get(key, () -> {
                if (!NumberUtil.isPositiveInteger(brandId) || !NumberUtil.isPositiveInteger(productId)) {
                    return CACHE_DEFAULT_RATIO;
                }
                BrandFactorDRO brandFactorDRO = brandRatioBService.getByBrandIdAndProductIdAndBizTypeAndPriceType(brandId, productId, bizType, brandPriceType);
                log.info("getBrandRatioNoCache brandFactorDRO = {}", brandFactorDRO);
                if (Objects.isNull(brandFactorDRO) || !PriceUtil.isPositive(brandFactorDRO.getRatio())) {
                    log.info("brandFactorDRO  or radio为空");
                    return CACHE_DEFAULT_RATIO;
                }
                return new BigDecimal(brandFactorDRO.getRatio()).floatValue();
            });
        } catch (Exception e) {
            log.error("缓存方式获取品牌系数失败:{},", e);
            throw new PlatException("缓存方式获取品牌系数失败");
        }
    }

    /**
     * 描述: 获取难度系数
     *
     * @param difficultId 难度系数id
     * @return com.zmn.plat.model.entity.base.difficult.ratio.DifficultRatio
     * @author guoqiao
     * @since 2021/8/27 11:07
     */
    private DifficultRatio getDifficultRatio(Integer difficultId) {
        try {
            return difficultCache.get(difficultId, () -> {
                DifficultRatio ratio = difficultRatioService.findByKey(difficultId);
                if (Objects.isNull(ratio)) {
                    return new DifficultRatio();
                }
                return ratio;
            });
        } catch (Exception e) {
            log.error("缓存方式获取难度系数失败:{},", e);
            throw new PlatException("缓存方式获取难度系数失败");
        }
    }


    @Override
    public void getTariffByOnOrder(List<ProductRelationDTO> relationDTOList, Integer channelId, Integer cityId, Integer bizType) {
        // 在途订单,只考虑计价器价格表（兼容线上环境，后续可删除）
        for (ProductRelationDTO relationDTO : relationDTOList) {
            Integer productId = relationDTO.getProductId();
            Map<Integer, Integer> traiffMap = new HashMap<>();
            // 是否支持计价器试点
            Boolean flag = channelPriceBService.checkByChannelIdAndCityIdAndTypeAndCateg(channelId, cityId, PilotConfigEnum.FEE_METER.getType(), relationDTO.getShowServCategId(), relationDTO.getShowCategId());
            if (flag) {
                // 查询计价器价格
                traiffMap = commonBService.getTariff(channelId, Arrays.asList(productId), ProductConsts.ERP_PRODUCT_TYPE, bizType, ProductDict.TRIFF_TYPE_TARIFF);
            }
            if (CollectionUtils.isEmpty(traiffMap)) {
                // 查询服务价格
                traiffMap = commonBService.getTariff(channelId, Arrays.asList(productId), ProductConsts.ERP_PRODUCT_TYPE, bizType, ProductDict.TRIFF_TYPE_SERVICE);
            }
            if (!CollectionUtils.isEmpty(traiffMap)) {
                // 计价器价格
                relationDTO.setTariffId(traiffMap.get(productId));
                relationDTO.setTariffType(ProductDict.TRIFF_TYPE_TARIFF);
            }
        }
    }

    @Override
    public void getTariffByPilot(List<ProductRelationDTO> relationDTOList, Integer channelId, Integer cityId, Integer bizType) {

        Integer avaliableChannelId = channelId;
        try {
            avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
            log.info("原渠道：{}，可用渠道：{}", channelId, avaliableChannelId);
        } catch (PlatException e) {
            log.error("无可用渠道");
        }

        for (ProductRelationDTO relationDTO : relationDTOList) {
            Integer productId = relationDTO.getProductId();
            // 是否支持计价器试点
            Boolean flag = channelPriceBService.checkByChannelIdAndCityIdAndTypeAndCateg(channelId, cityId, PilotConfigEnum.FEE_METER.getType(), relationDTO.getShowServCategId(), relationDTO.getShowCategId());
            if (flag) {
                // 是否支持提前付试点
                Boolean flag2 = channelPriceBService.checkByChannelIdAndCityIdAndTypeAndCateg(channelId, cityId, PilotConfigEnum.PAY_ADVANCE.getType(), relationDTO.getShowServCategId(), relationDTO.getShowCategId());
                if (flag2) {
                    // 查询提前付价格
                    Map<Integer, Integer> traiffMapAdv = commonBService.getTariff(avaliableChannelId, Arrays.asList(productId), ProductConsts.ERP_PRODUCT_TYPE, bizType, ProductDict.TRIFF_TYPE_ADVANCE);
                    if (!CollectionUtils.isEmpty(traiffMapAdv)) {
                        // 提前付价格
                        relationDTO.setTariffId(traiffMapAdv.get(productId));
                        relationDTO.setTariffType(ProductDict.TRIFF_TYPE_ADVANCE);
                        continue;
                    }
                }
                // 查询计价器价格
                Map<Integer, Integer> traiffMap = commonBService.getTariff(avaliableChannelId, Arrays.asList(productId), ProductConsts.ERP_PRODUCT_TYPE, bizType, ProductDict.TRIFF_TYPE_TARIFF);
                if (!CollectionUtils.isEmpty(traiffMap)) {
                    // 计价器价格
                    relationDTO.setTariffId(traiffMap.get(productId));
                    relationDTO.setTariffType(ProductDict.TRIFF_TYPE_TARIFF);
                    continue;
                }
            }
            // 查询服务价格
            Map<Integer, Integer> traiffMapServ = commonBService.getTariff(avaliableChannelId, Arrays.asList(productId), ProductConsts.ERP_PRODUCT_TYPE, bizType, ProductDict.TRIFF_TYPE_SERVICE);
            if (!CollectionUtils.isEmpty(traiffMapServ)) {
                // 服务价格
                relationDTO.setTariffId(traiffMapServ.get(productId));
                relationDTO.setTariffType(ProductDict.TRIFF_TYPE_SERVICE);
            }
        }
    }

    @Override
    public void filterTariff(List<ProductRelationDTO> relationDTOList, Integer groupType, Boolean flag) {

        if (CollectionUtils.isEmpty(relationDTOList)) {
            return;
        }

        // 过滤掉 TariffType 为空或者 为1的类型
        List<ProductRelationDTO> collect = relationDTOList.stream()
                .filter(e -> Objects.nonNull(e.getTariffType()))
                .filter(e -> {
                    if (Objects.equals(true, flag)) {
                        return !Objects.equals(e.getTariffType(), ProductDict.TRIFF_TYPE_SERVICE);
                    }
                    return true;
                }).collect(Collectors.toList());

        // 根据前台产品id分组
        Map<Integer, List<ProductRelationDTO>> listMap = new HashMap<>(relationDTOList.size());
        if (Objects.equals(ProductConsts.ERP_PRODUCT_TYPE, groupType)) {
            listMap = collect.stream().collect(Collectors.groupingBy(ProductRelationDTO::getProductId));
        } else if (Objects.equals(ProductConsts.EC_PRODUCT_TYPE, groupType)) {
            listMap = collect.stream().collect(Collectors.groupingBy(ProductRelationDTO::getShowProductId));
        } else if (Objects.equals(ProductConsts.ET_PRODUCT_TYPE, groupType)) {
            listMap = collect.stream().collect(Collectors.groupingBy(ProductRelationDTO::getTariffProductId));
        }

        relationDTOList.clear();
        // 同一分组下 取优先级最高的那条数据
        listMap.forEach((key, value) -> {
            // 对相同key的价格表类型tariffType  3提前付 优先于 2计价器
            List<ProductRelationDTO> dtoList = value.stream().collect(
                    Collectors.groupingBy(ProductRelationDTO::getTariffType, TreeMap::new, Collectors.toList()))
                    .lastEntry().getValue();
            relationDTOList.addAll(dtoList);
        });
    }

    @Override
    @Cacheable(cacheNames = "redis1h", key = "'price:getTariff:channelId:'+#p0+':productIdList:'+#p1+':showType:'+#p2+':bizType:'+#p3+':tariffType:'+#p4", unless = "#result == null")
    public Map<Integer, Integer> getTariff(Integer channelId, List<Integer> productIdList, Integer showType, Integer bizType, Integer tariffType) {
        Integer avaliableChannelId = channelId;
        try {
            avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            log.error("无可用渠道");
        }
        // 后台产品id集合
        List<Integer> productIds = Optional.ofNullable
                (servProductBService.listProductRalationByIdListAndShowType(productIdList, showType))
                .orElse(Collections.emptyList())
                .stream()
                .filter(e -> {
                    if (Objects.equals(ProductDict.TRIFF_TYPE_TARIFF, tariffType) || Objects.equals(ProductDict.TRIFF_TYPE_ADVANCE, tariffType)) {
                        return Objects.equals(e.getTariffStatus(), GlobalConsts.YES) && Objects.equals(e.getTariffProductStatus(), GlobalConsts.YES);
                    }
                    return true;
                })
                .filter(e -> {
                    ServProduct product = servProductService.findByKeyWithCache(e.getProductId());
                    if (Objects.nonNull(product) && !product.getBizType().contains(String.valueOf(bizType))) {
                        return false;
                    }
                    if (Objects.equals(product.getProductType(), ProductConsts.SERV_PRODUCT_TYPE_CHANNEL)
                            && !Objects.equals(product.getChannelId(), channelId)) {
                        return false;
                    }
                    return true;
                })
                .map(e -> e.getProductId())
                .distinct()
                .collect(Collectors.toList());

        Map<Integer, Integer> result = new HashMap(productIds.size());
        if (CollectionUtils.isEmpty(productIds)) {
            return result;
        }

        // 查询渠道价格表
        ChannelServiceTariffVO channelTariff = channelTariffService.findFaultTariffByChannelId(avaliableChannelId, bizType, tariffType);

        // 查询符合条件的价格表id集合 serv_service_tariff
        List<Integer> tariffIds = Optional.ofNullable(serviceTariffService.listAll())
                .orElse(Collections.emptyList())
                .stream()
                .filter(e -> Objects.equals(bizType, e.getBizType())
                        && Objects.equals(tariffType, e.getTariffType())
                        && Objects.equals(GlobalConsts.YES, e.getStatus()))
                .map(e -> e.getTariffId())
                .collect(Collectors.toList());


        for (Integer productId : productIds) {
            // 查询产品价格表 serv_product_tariff
            ProductTariffQuery productTariffQuery = new ProductTariffQuery();
            productTariffQuery.setProductId(productId);
            productTariffQuery.setStatus(GlobalConsts.YES);
            List<ProductTariffVO> productTariffList = Optional.ofNullable(productTariffService.listByQueryWithCache(productTariffQuery))
                    .orElse(Collections.emptyList())
                    .stream()
                    .filter(e -> tariffIds.contains(e.getTariffId()))
                    .collect(Collectors.toList());

            // 检查渠道价格表是否可用
            if (Objects.nonNull(channelTariff) && NumberUtil.isNotNullOrZero(channelTariff.getTariffId())) {
                List<Integer> tariffIdList = productTariffList.stream().map(e -> e.getTariffId()).collect(Collectors.toList());
                if (tariffIdList.contains(channelTariff.getTariffId())) {
                    // 判断产品在当前价格表下是否可以用 serv_product_tariff_group_item
                    ProductTariffGroupItemQuery itemQuery = new ProductTariffGroupItemQuery();
                    itemQuery.setProductId(productId);
                    itemQuery.setTariffId(channelTariff.getTariffId());
//                    if (Objects.equals(ProductDict.TRIFF_TYPE_TARIFF, tariffType) || Objects.equals(ProductDict.TRIFF_TYPE_ADVANCE, tariffType)) {
//                        itemQuery.setCategIds(ITEM_CATEG_LIST);
//                    }
                    int count = productTariffGroupItemService.countByQuery(itemQuery);
                    if (count > 0) {
                        result.put(productId, channelTariff.getTariffId());
                        continue;
                    }
                }
            }

            // 产品默认价格表id
            Integer tariffId = productTariffList.stream()
                    .filter(e -> Objects.equals(GlobalConsts.YES, e.getGeneral()))
                    .map(e -> e.getTariffId())
                    .findFirst()
                    .orElse(0);

            if (NumberUtil.isNotNullOrZero(tariffId)) {
                // 判断产品在当前价格表下是否可以用 serv_product_tariff_group_item
                ProductTariffGroupItemQuery itemQuery = new ProductTariffGroupItemQuery();
                itemQuery.setProductId(productId);
                itemQuery.setTariffId(tariffId);
//                if (Objects.equals(ProductDict.TRIFF_TYPE_TARIFF, tariffType) || Objects.equals(ProductDict.TRIFF_TYPE_ADVANCE, tariffType)) {
//                    itemQuery.setCategIds(ITEM_CATEG_LIST);
//                }
                int count = productTariffGroupItemService.countByQuery(itemQuery);
                if (count > 0) {
                    result.put(productId, tariffId);
                    continue;
                }
            }
        }
        return result;
    }

    @Override
    @Cacheable(cacheNames = "redis1h", key = "'price:checkTariff:channelId:'+#p0+':productId:'+#p1+':showType:'+#p2+':bizType:'+#p3", unless = "#result == null")
    public Boolean checkTariff(Integer channelId, Integer productId, Integer showType, Integer bizType) {
        // 前后台计价器关系
        List<Integer> productIdList = Optional.ofNullable
                (servProductBService.listProductRalationByIdListAndShowType(Arrays.asList(productId), showType))
                .orElse(Collections.emptyList())
                .stream()
                .filter(e -> Objects.equals(e.getTariffStatus(), GlobalConsts.YES)
                        && Objects.equals(e.getTariffProductStatus(), GlobalConsts.YES))
                .map(e -> e.getProductId())
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(productIdList)) {
            return false;
        }
        // 查询价格
        Map<Integer, Integer> traiffMap = commonBService.getTariff(channelId, productIdList, ProductConsts.ERP_PRODUCT_TYPE, bizType, ProductDict.TRIFF_TYPE_TARIFF);
        if (CollectionUtils.isEmpty(traiffMap)) {
            return false;
        }
        return true;
    }

}
